home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Die Speccy' 97
/
Die Speccy' 97.iso
/
amiga_system
/
the_aminet
/
dev
/
misc
/
mkdepend_1_1.lha
/
MkDepend-1.1
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-14
|
32KB
|
1,286 lines
/*
$VER: main:c 1.1 (12-Oct-95) Copyright ⌐ by Lars Dⁿning
*/
/*---------------------------------------------------------------------------
** Main module of MkDepend.
**
** Copyright ⌐ 1995 Lars Dⁿning - All rights reserved.
** Permission granted for non-commercial use.
**---------------------------------------------------------------------------
** The module implements the argument parsing and the control flow.
**
** Usage:
** mkdepend {-i|INCLUDE <includepath>[::<symbol>]}
** {-x|EXCEPT <filepattern>}
** {-s|SUFFIX <src_ext>{,<src_ext>}[:<obj_ext>] | :<obj_ext>}
** {-p|OBJPAT <src_ext>{,<src_ext>}:<obj_pattern>
** [-f|MAKE <makefile>]
** [-v|VERBOSE]
** {<filepattern>}
**
** The <objpattern> recognizes as meta-symbols:
** %s: the full sourcename (w/o suffix)
** %[-][<][<number>]p: the path part of the sourcename
** <number>: skip first <number> directories of the path, defaults to 0.
** < : directories are counted from the end.
** - : use, don't skip the counted directories.
** %n: the base of the sourcename (w/o suffix)
** %%: the character %
** %x: the character 'x' for every other character.
**
**---------------------------------------------------------------------------
** C: DICE 3.01
**---------------------------------------------------------------------------
** [lars] Lars Dⁿning; Am Wendenwehr 25; D-38114-Braunschweig;
** Germany; Tel. 49-531-345692
**---------------------------------------------------------------------------
** 11-Sep-95 [lars]
** 12-Oct-95 [lars] %p expanded to %[-][<][<number>]p
** 13-Oct-95 [lars] current
**---------------------------------------------------------------------------
*/
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <exec/types.h>
#include <exec/libraries.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include "reader.h"
#include "nodes.h"
extern struct Library *SysBase;
/*-------------------------------------------------------------------------*/
/* Release version number, should match the version number in the Makefiles */
#define VERSION "1.1"
/* Dynamic string array */
typedef struct sarray
{
int size; /* Number of used strings */
int alloc; /* Number of allocated string pointers */
char ** strs; /* Array of string pointers */
} SArray;
/* Program arguments */
static short bVerbose = FALSE; /* TRUE: Verbose action */
static SArray aFiles = { 0, 0, NULL }; /* Source files */
static SArray aAvoid = { 0, 0, NULL }; /* Source files to avoid */
static SArray aIncl = { 0, 0, NULL }; /* Include paths */
static SArray aSymbol = { 0, 0, NULL }; /* Include path symbols */
static SArray aSrcExt = { 0, 0, NULL }; /* Source file extensions */
static SArray aObjExt = { 0, 0, NULL }; /* Associated object file extensions */
static SArray aObjPat = { 0, 0, NULL }; /* Associated object file patterns */
static char * sObjExt = NULL; /* Default object file extension */
static char * sMake = NULL; /* Name of the Makefile */
/* Misc Variables */
static char * aPgmName = NULL; /* Name of the program executable */
char * aVersion = "$VER: MkDepend " VERSION " (" __DATE__ ")";
static struct stat aMakeStat; /* Stat buffer for the Makefile */
static int bMakeExists; /* TRUE: Old Makefile exists */
static int returncode = RETURN_OK; /* Global return code */
/*-----------------------------------------------------------------------*/
static void
set_rc (int code, int bAbort)
/* Set the global returncode to <code> given that <code> is higher
* than the current one.
* If <bAbort>, exit immediately then.
*/
{
if (code > returncode)
returncode = code;
if (bAbort)
exit(returncode);
}
/*-----------------------------------------------------------------------*/
static int
chmod (char *file, long mode)
/* Set the access mode of a file.
* For Amiga-OS, only the owner access can be set.
*/
{
BPTR lock;
struct FileInfoBlock *info;
int rc;
/* Unix mode 'rwx??????' => DOS mode 'rwxw' aka 'rwxd'.
** Well, this should be done using the FIB* constants from dos.h
** but they will hardly change and 'knowing' them keeps this a one-liner.
** Note that the Amiga-OS bits disallow the operation when set.
*/
mode = ~((mode & 0700) >> 5 | (mode & 0200) >> 7) & 017;
info = (struct FileInfoBlock *) malloc(sizeof (struct FileInfoBlock));
if (info == NULL) return -1;
rc = -1;
if ((lock = Lock(file, SHARED_LOCK)) == NULL) goto chmod_exit;
if (Examine(lock, info) == DOSFALSE) goto chmod_exit;
UnLock(lock);
if (SetProtection(file, (info->fib_Protection & (~017)) | mode) != DOSFALSE)
rc = 0;
chmod_exit:
free (info);
return rc;
}
/*-----------------------------------------------------------------------*/
static void
CheckStacksize (LONG try_size)
/* Check the stacksize of this process against try_size.
* If the actual stacksize is smaller, print a message and exit.
*/
{
struct Task *pThis;
pThis = (struct Task *)FindTask(NULL);
/* Sanity checks, shouldn't happen anyway */
assert(pThis && pThis->tc_Node.ln_Type == NT_PROCESS);
if ((LONG)((char *)pThis->tc_SPUpper - (char *)pThis->tc_SPLower) < try_size)
{
printf("%s: Needs at least %ld KByte stack.\n", aPgmName, (try_size+512) >> 10);
exit(RETURN_ERROR);
}
}
/*-------------------------------------------------------------------------*/
static void
check_os2 (void)
/* Check if OS2 is available. If not, print a message and exit.
*/
{
char *sNeedsOS2 = "Fatal: Needs OS 2.0 or better.\n";
if (SysBase->lib_Version < 36)
{
Write(Output(), sNeedsOS2, strlen(sNeedsOS2));
set_rc(RETURN_FAIL, 1);
}
}
/*-------------------------------------------------------------------------*/
static void
exit_doserr (int code)
/* Print a message according to IoErr(), then exit with <code>.
*/
{
PrintFault(IoErr(), aPgmName);
set_rc(code, 1);
}
/*-------------------------------------------------------------------------*/
static void
exit_nomem (int code)
/* Print a "Out of Memory" message and exit with <code>.
*/
{
printf("%s: Out of memory.\n", aPgmName);
set_rc(code, 1);
}
/*-------------------------------------------------------------------------*/
static int
array_addfile (SArray *pArray, char * pName)
/* Add a copy of <*pName> to the string array <pArray>.
* Return 0 on success, non-0 on error.
* If pName is NULL, the array is simply extended by a NULL pointer.
*/
{
char ** pStrs;
assert(pArray->size <= pArray->alloc);
if (pArray->size+1 > pArray->alloc)
{
pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+4));
if (!pStrs)
return 1;
pArray->strs = pStrs;
pArray->alloc += 4;
}
else
pStrs = pArray->strs;
if (pName)
{
pStrs[pArray->size] = strdup(pName);
if (!pStrs[pArray->size])
return 1;
}
else
pStrs[pArray->size] = NULL;
pArray->size++;
return 0;
}
/*-------------------------------------------------------------------------*/
static int
array_addlist (SArray *pArray, int count, char ** pList)
/* Add the <count> string pointers from <pList> to string array <pArray>.
* pList may be freed after return, the strings themselves are still
* referenced (by pArray then).
* Return 0 on success, non-0 else.
*/
{
char ** pStrs;
int i;
assert(pList);
if (!count)
return 0;
assert(pArray->size <= pArray->alloc);
if (pArray->size+count > pArray->alloc)
{
pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+count));
if (!pStrs)
return 1;
pArray->strs = pStrs;
pArray->alloc += count;
}
else
pStrs = pArray->strs;
for (i = 0; i < count; i++)
pStrs[pArray->size++] = pList[i];
return 0;
}
/*-------------------------------------------------------------------------*/
static int
add_expfile (SArray *pArray, char * pName)
/* Glob filename <*pName> and add the filenames to string array <pArray>.
* Return 0 on success, non-0 else.
*
* The function uses DICE' supplied function expand_args() which does not
* implement all possible wildcard patterns.
*/
{
char * argv[] = { NULL, pName, NULL };
int argc = 2;
char ** xargv;
int xargc;
int rc;
if (expand_args(argc, argv, &xargc, &xargv))
{
printf("%s: Error expanding %s\n", aPgmName, pName);
set_rc(RETURN_ERROR, 1);
}
assert(xargc > 1);
rc = 0;
if (xargc > 1)
{
rc = array_addlist(pArray, xargc-1, xargv+1);
if (rc)
{
while (--xargc > 0)
if (xargv[xargc])
free(xargv[xargc]);
}
free(xargv);
}
return rc;
}
/*-------------------------------------------------------------------------*/
static void
getargs (void)
/* Get the arguments from the commandline.
* Unfortunately we have to emulate ReadArgs() as we have several /M values
* in our template.
*/
{
int i; /* all purpose */
#define BUFSIZE 1024
char aBuffer[BUFSIZE]; /* Argument buffer */
char aArgBuf[BUFSIZE]; /* Source buffer for separator less arguments */
long item, arg; /* Result from ReadItem(), FindArg() */
struct CSource aArgSrc; /* For postponed arguments */
enum {
NoArg, QuesFound, OtherArg, QuesPending
} eHelp;
enum {
Standard, ParseMake, ParseIncl, ParseExcept, ParseSuffix, ParseObjpat
} eMulti;
/* General command template */
char * sTemplate
= "-F=MAKE/K,-I=INCLUDE/K,-X=EXCEPT/K,-S=SUFFIX/K,-P=OBJPAT/K,-V=VERBOSE/S,FILES/M";
#define TEMP_MAKE 0
#define TEMP_INCLUDE 1
#define TEMP_EXCEPT 2
#define TEMP_SUFFIX 3
#define TEMP_PATTERN 4
#define TEMP_VERBOSE 5
#define TEMP_FILES 6
/* Options which allow for no separator */
char * sAbbrev
= "-F/K,-I/K,-X/K,-S/K,-P/K";
#define ABBREV_MAKE 0
#define ABBREV_INCLUDE 1
#define ABBREV_EXCEPT 2
#define ABBREV_SUFFIX 3
#define ABBREV_PATTERN 4
/* Translation table abbrev indices to template indices */
int aA2T[] = { TEMP_MAKE, TEMP_INCLUDE, TEMP_EXCEPT, TEMP_SUFFIX, TEMP_PATTERN };
eHelp = NoArg;
eMulti = Standard;
aArgSrc.CS_Buffer = NULL;
while(1)
{
if (eHelp == QuesPending)
{
aBuffer[0] = '?';
aBuffer[1] = '\0';
item = ITEM_UNQUOTED;
eHelp = OtherArg;
}
else
{
aBuffer[0] = '\0';
item = ReadItem(aBuffer, BUFSIZE, aArgSrc.CS_Buffer ? &aArgSrc : NULL);
}
if (ITEM_EQUAL == item)
item = ITEM_UNQUOTED;
if (ITEM_ERROR == item)
exit_doserr(RETURN_ERROR);
if (ITEM_NOTHING == item)
{
if (!aArgSrc.CS_Buffer && eHelp != QuesFound)
break; /* outer while(1) */
if (aArgSrc.CS_Buffer)
aArgSrc.CS_Buffer = NULL;
else
{
FGetC(Input()); /* re-read newline */
Write(Output(), sTemplate, strlen(sTemplate));
Write(Output(), ": ", 2);
eHelp = NoArg;
eMulti = Standard;
}
continue;
}
if (eHelp == NoArg && eMulti == Standard && !strcmp(aBuffer, "?"))
{
eHelp = QuesFound;
continue;
}
/* At this point, we have an arg beside '?' so mark the '?'
* for reinsertion
*/
if (eHelp == QuesFound)
{
eHelp = QuesPending;
}
/* Check if the argument is a keyword */
arg = -1;
if (ITEM_UNQUOTED == item && !aArgSrc.CS_Buffer)
{
/* Shortcuts need no separator */
if (aBuffer[0] == '-' && aBuffer[1] != '\0' && aBuffer[2] != '\0')
{
char aTmp[3] = { '-', aBuffer[1], '\0' };
arg = FindArg(sAbbrev, aTmp);
if (arg != -1)
{
int len;
arg = aA2T[arg];
strcpy(aArgBuf, aBuffer+2);
len = strlen(aArgBuf);
aArgBuf[len] = '\n'; /* ReadItem() needs this as terminator */
aArgBuf[len+1] = '\0';
aBuffer[2] = '\0';
aArgSrc.CS_Buffer = aArgBuf;
aArgSrc.CS_Length = len+1;
aArgSrc.CS_CurChr = 0;
}
}
if (arg == -1)
arg = FindArg(sTemplate, aBuffer);
}
/* arg == -1: aBuffer is an argument
* arg != -1: bufindex == 0: aBuffer is keyword
*/
/* Evaluate keyword if any */
switch(arg)
{
case TEMP_MAKE:
eMulti = ParseMake;
break;
case TEMP_INCLUDE:
eMulti = ParseIncl;
break;
case TEMP_EXCEPT:
eMulti = ParseExcept;
break;
case TEMP_SUFFIX:
eMulti = ParseSuffix;
break;
case TEMP_PATTERN:
eMulti = ParseObjpat;
break;
case TEMP_VERBOSE:
bVerbose = 1;
break;
default:
assert(arg == -1);
break;
}
if (arg != -1)
continue; /* of while(1) */
/* Assign argument value (if any) */
switch (eMulti)
{
case Standard:
if (ITEM_QUOTED == item)
i = array_addfile(&aFiles, aBuffer);
else
i = add_expfile(&aFiles, aBuffer);
if (i)
exit_nomem(RETURN_FAIL);
break;
case ParseMake:
if (sMake)
free(sMake);
sMake = strdup(aBuffer);
if (!sMake)
exit_nomem(RETURN_FAIL);
break;
case ParseExcept:
if (ITEM_QUOTED == item)
i = array_addfile(&aAvoid, aBuffer);
else
i = add_expfile(&aAvoid, aBuffer);
if (i)
exit_nomem(RETURN_FAIL);
break;
case ParseIncl:
{
char * pSym, * pMark;
/* Allow for <path>::<symbol> notation */
pSym = NULL;
pMark = aBuffer+strlen(aBuffer);
if (pMark != aBuffer)
{
pMark--;
while (!pSym && pMark >= aBuffer+1)
{
if (':' != *pMark)
{
pMark--;
continue;
}
if (':' != *(pMark-1))
{
pMark -= 2;
continue;
}
pSym = pMark+1;
*(pMark-1) = '\0';
}
}
if (pSym && !strlen(pSym))
pSym = NULL;
i = array_addfile(&aSymbol, pSym);
if (i)
exit_nomem(RETURN_FAIL);
/* Make sure <path> ends in a ':' or '/' */
pMark = aBuffer+strlen(aBuffer);
if (pMark > aBuffer && ':' != *(pMark-1) && '/' != *(pMark-1))
{
*pMark = '/';
*(pMark+1) = '\0';
}
i = array_addfile(&aIncl, aBuffer);
if (i)
exit_nomem(RETURN_FAIL);
}
break;
case ParseSuffix:
case ParseObjpat:
{
char * pMark, *pOsfix;
/* Allow for <src_suffix>:<obj_suffix> notation */
pOsfix = NULL;
pMark = aBuffer+strlen(aBuffer);
if (pMark != aBuffer)
{
pMark--;
while (!pOsfix && pMark >= aBuffer)
{
if (':' != *pMark)
{
pMark--;
continue;
}
pOsfix = pMark+1;
*pMark = '\0';
}
}
if (pOsfix && !strlen(pOsfix))
pOsfix = NULL;
if (ParseObjpat == eMulti && !pOsfix)
{
printf("%s: Object pattern missing in argument.\n", aPgmName);
set_rc(RETURN_WARN, 0);
break;
}
/* :<obj_suffix> alone defines default object suffix */
if (pOsfix && !strlen(aBuffer))
{
if (sObjExt)
free(sObjExt);
sObjExt = strdup(pOsfix);
if (!sObjExt)
exit_nomem(RETURN_FAIL);
}
else
{
char * pSfix;
/* Allow for <sfix1>,<sfix2>,...,<sfixn> for source suffixes */
for ( pSfix = aBuffer
; pMark = strchr(pSfix, ',')
; pSfix = pMark+1
)
{
*pMark = '\0';
if (strlen(pSfix))
{
if ( array_addfile(&aSrcExt, pSfix)
|| (ParseSuffix == eMulti ? array_addfile(&aObjExt, pOsfix)
: array_addfile(&aObjPat, pOsfix)
)
)
exit_nomem(RETURN_FAIL);
}
}
if (strlen(pSfix))
{
if ( array_addfile(&aSrcExt, pSfix)
|| (ParseSuffix == eMulti ? array_addfile(&aObjExt, pOsfix)
: array_addfile(&aObjPat, pOsfix)
)
)
exit_nomem(RETURN_FAIL);
}
}
}
break;
default:
assert(0);
}
eMulti = Standard;
} /* while(1) */
#undef BUFSIZE
#undef TEMP_MAKE
#undef TEMP_INCLUDE
#undef TEMP_EXCEPT
#undef TEMP_SUFFIX
#undef TEMP_PATTERN
#undef TEMP_VERBOSE
#undef TEMP_FILES
#undef ABBREV_MAKE
#undef ABBREV_INCLUDE
#undef ABBREV_EXCEPT
#undef ABBREV_SUFFIX
#undef ABBREV_PATTERN
}
/*-------------------------------------------------------------------------*/
static int
readfiles (void)
/* Read and analyse all files.
* If a file can't be read, print a message.
* Return 0 if all went well, RETURN_WARN if one of the files could not be
* found, RETURN_ERROR if one of the files could not be read properly.
*/
{
int rc; /* Return value */
struct stat aStat; /* buffer for stat() */
Node * pNode; /* Node of the file under examination */
int srcRead; /* Number of source files read */
int index; /* index in the aIncl array */
char aName[FILENAME_MAX+1];
int i;
const char * pName; /* Includefile name returned by reader */
rc = 0;
srcRead = 0;
aName[FILENAME_MAX] = '\0';
while (pNode = nodes_todo())
{
/* Search the correct directory to read from */
index = -1;
pNode->iInclude = 0;
strcpy(aName, pNode->pName);
i = stat(aName, &aStat);
if (i && !(pNode->flags & NODE_SOURCE))
{
for (index = 0; i && index < aIncl.size; index++)
{
strcpy(aName, aIncl.strs[index]);
strcat(aName, pNode->pName);
assert(aName[FILENAME_MAX] == '\0');
i = stat(aName, &aStat);
}
if (!i)
pNode->iInclude = index;
}
if (i || !reader_open(aName))
{
if (!i)
perror("mkdepend");
if (rc < RETURN_ERROR)
rc = RETURN_WARN;
printf("%s: Warning: Cant't read '%s'.\n", aPgmName, aName);
continue;
}
if (bVerbose)
{
printf(" reading %-65s\r", aName); fflush(stdout);
}
while (pName = reader_get())
{
if (nodes_depend(pNode, pName))
{
if (bVerbose)
printf("%+-78s\r", "");
reader_close();
exit_nomem(RETURN_FAIL);
}
}
if (bVerbose)
printf("%+-78s\r", "");
if (!reader_eof() || reader_close())
{
perror("mkdepend");
printf("%s: Error reading '%s'\n", aPgmName, aName);
rc = RETURN_ERROR;
}
else if (pNode->flags & NODE_SOURCE)
{
srcRead++;
}
} /* while (nodes_todo()) */
if (!srcRead)
{
printf("%s: No source file read.\n", aPgmName);
rc = RETURN_ERROR;
}
if (bVerbose)
fflush(stdout);
return rc;
}
/*-------------------------------------------------------------------------*/
static void
make_objname ( char *pBuf, const char *pName, int slen
, const char * pObjExt, const char *pObjPat
)
/* Construct the name of the dependency target.
*
* pBuf : Buffer to construct the name in.
* pName : Name of the sourcefile.
* slen : Length of the sourcefile suffix.
* pObjExt: Object extensions for this sourcefile, may be NULL.
* pObjPat: Object pattern for this sourcefile, may be NULL.
*
* If pObjPat is not NULL, the pattern is used to construct the name.
* If pObjPat is NULL, the pObjExt string is appended to the sourcefile
* name (minus its source suffix) to construct the name. If pObjExt is
* NULL, the default object extension is used.
*/
{
int nlen, plen;
char * pBasename;
char * pSrc, *pDst, *pMark, ch;
short flags;
long number;
#define GOT_MINUS (1<<0)
#define GOT_ANGLE (1<<1)
#define GOT_NUMBER (1<<2)
#define NOT_DONE (1<<3)
#define NO_PATTERN (1<<4)
nlen = strlen(pName)-slen;
if (!pObjPat)
{
strcpy(pBuf, pName);
if (pObjExt)
strcpy(pBuf+nlen, pObjExt);
else
strcpy(pBuf+nlen, sObjExt);
return;
}
pBasename = FilePart(pName);
plen = pBasename-pName;
pSrc = pObjPat;
pDst = pBuf;
while ('\0' != (ch = *pSrc++))
{
if (ch != '%')
{
*pDst++ = ch;
continue;
}
pMark = pSrc;
flags = 0;
do
{
ch = *pSrc++;
switch(ch)
{
case '-':
if (flags & (GOT_MINUS|GOT_ANGLE|GOT_NUMBER))
flags = NO_PATTERN;
else
flags |= GOT_MINUS|NOT_DONE;
break;
case '<':
if (flags & (GOT_ANGLE|GOT_NUMBER))
flags = NO_PATTERN;
else
flags |= GOT_ANGLE|NOT_DONE;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (flags & GOT_NUMBER)
flags = NO_PATTERN;
else
{
char * pTail;
number = strtol(pSrc-1, &pTail, 10);
pSrc = pTail;
flags |= GOT_NUMBER|NOT_DONE;
}
break;
case 's':
strncpy(pDst, pName, nlen);
pDst += nlen;
flags = 0;
break;
case 'p':
if (pName != pBasename
&& (!(flags & GOT_MINUS) || (flags & GOT_NUMBER))
)
{
char * cp;
size_t cplen;
cp = pName;
cplen = plen;
if (flags & GOT_NUMBER)
{
if (flags & GOT_ANGLE)
{
cp = pName+plen;
number++;
while (number)
{
--cp;
if (*cp == '/' || *cp == ':')
{
number--;
if (!number)
cp++;
}
if (cp == pName)
break;
}
}
else
{
cp = pName;
while (number && cp != pBasename)
{
if (*cp == '/' || *cp == ':')
{
number--;
}
cp++;
}
}
/* cp now points to the character after the
* determined path part.
*/
if (flags & GOT_MINUS)
{
cplen = cp - pName;
cp = pName;
}
else
cplen = plen - (cp-pName);
}
if (cplen)
{
strncpy(pDst, cp, cplen);
pDst += cplen;
}
}
flags = 0;
break;
case 'n':
strncpy(pDst, pBasename, nlen-plen);
pDst += nlen-plen;
flags = 0;
break;
case '%':
*pDst++ = '%';
flags = 0;
break;
default:
flags = NO_PATTERN;
break;
}
}
while (flags & NOT_DONE);
if (flags & NO_PATTERN)
pSrc = pMark; /* to be read again as normal text */
}
*pDst = '\0';
#undef GOT_MINUS
#undef GOT_ANGLE
#undef GOT_NUMBER
#undef NOT_DONE
#undef NO_PATTERN
}
/*-------------------------------------------------------------------------*/
static int
output (void)
/* Output the collected dependencies into the Makefile.
* Return 0 on success, RETURN_WARN on a mild error, RETURN_ERROR on a
* severe error.
*/
{
int rc;
char * pBackup; /* Name of the Makefilebackup */
Node * pNode;
pBackup = NULL;
/* Rename old Makefile if necessary */
if (bMakeExists)
{
pBackup = (char *)malloc(strlen(sMake)+4);
strcpy(pBackup, sMake);
strcat(pBackup, ".bak");
remove(pBackup);
if (rename(sMake, pBackup))
{
perror("mkdepend");
printf("%s: Can't rename '%s' to '%s'.\n", aPgmName, sMake, pBackup);
free(pBackup);
return RETURN_ERROR;
}
}
rc = RETURN_OK;
do
{
/* Open files */
if (reader_openrw(pBackup, sMake))
{
perror("mkdepend");
printf("%s: Can't write '%s'\n", aPgmName, sMake);
rc = RETURN_ERROR;
break;
}
if (bVerbose)
{
printf(" %s '%s'\r", bMakeExists ? "updating" : "creating", sMake); fflush(stdout);
}
/* Copy the Makefile up to the tagline */
if (reader_copymake("# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS FOLLOW ---\n"))
{
int i = errno;
if (bVerbose)
printf("%+-78s\r", "");
errno = i;
perror("mkdepend");
printf("%s: Error copying '%s' to '%s'.\n", aPgmName, pBackup, sMake);
rc = RETURN_ERROR;
break;
}
/* Walk and output the dependencies */
nodes_initwalk();
while (rc != RETURN_ERROR && (pNode = nodes_inorder()))
{
if ((pNode->flags & (NODE_SOURCE|NODE_AVOID)) == NODE_SOURCE)
{
Node * pRNode;
NodeRef * pList, * pRef;
int suffix; /* Suffix index */
int slen; /* Linelen so far */
int len;
char aObjname[FILENAME_MAX+1];
aObjname[FILENAME_MAX] = '\0';
pList = nodes_deplist(pNode);
assert(pList);
pRef = pList;
/* Check for a given suffix.
* Search backwards in case later definitions overwrote
* earlier ones.
*/
slen = strlen(pNode->pName);
for (suffix = aSrcExt.size-1; suffix >= 0; suffix--)
{
len = strlen(aSrcExt.strs[suffix]);
if (!strcmp(pNode->pName+slen-len, aSrcExt.strs[suffix]))
break;
}
/* Construct the name of the dependency target and write it */
if (suffix >= 0)
{
make_objname( aObjname, pNode->pName, len
, aObjExt.size ? aObjExt.strs[suffix] : NULL
, aObjPat.size ? aObjPat.strs[suffix] : NULL
);
assert(aObjname[FILENAME_MAX] == '\0');
if (reader_write(aObjname))
{
rc = RETURN_ERROR;
break; /* outer while */
}
slen = strlen(aObjname);
}
else
{
if (reader_write(pNode->pName))
{
rc = RETURN_ERROR;
break; /* outer while */
}
pRef = pRef->pNext;
}
if (reader_write(" : "))
{
rc = RETURN_ERROR;
break; /* outer while */
}
slen += 3;
for ( ; rc != RETURN_ERROR && pRef; pRef = pRef->pNext)
{
pRNode = pRef->pNode;
/* Construct the name of the dependee */
aObjname[0] = ' ';
aObjname[1] = '\0';
if (pRNode->iInclude)
{
if (aSymbol.strs[pRNode->iInclude-1])
strcat(aObjname, aSymbol.strs[pRNode->iInclude-1]);
else
strcat(aObjname, aIncl.strs[pRNode->iInclude-1]);
strcat(aObjname, pRNode->pName);
}
else
{
strcat(aObjname, pRNode->pName);
}
assert(aObjname[FILENAME_MAX] == '\0');
len = strlen(aObjname);
/* Fit it into the line */
if (slen > 0)
{
if (slen+len > 75)
{
if (reader_writen(" \\\n", 3))
{
rc = RETURN_ERROR;
break; /* inner while */
}
slen = 0;
}
}
if (!slen)
{
if (reader_writen(" ", 3))
{
rc = RETURN_ERROR;
break; /* inner while */
}
slen = 3;
}
if (reader_writen(aObjname, len))
{
rc = RETURN_ERROR;
break; /* inner while */
}
slen += len;
} /* for () */
nodes_freelist(pList);
if (slen && reader_writen("\n\n", 2))
{
rc = RETURN_ERROR;
break; /* outer while */
}
} /* if (source node) */
} /* while (treewalk */
if (rc == RETURN_ERROR)
{
int i = errno;
if (bVerbose)
printf("%+-78s\r", "");
errno = i;
perror("mkdepend");
printf("%s: Error writing '%s'.\n", aPgmName, sMake);
rc = RETURN_ERROR;
break;
}
if (reader_copymake2("# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS PRECEDE ---\n"))
{
int i = errno;
if (bVerbose)
printf("%+-78s\r", "");
errno = i;
perror("mkdepend");
printf("%s: Error copying '%s' to '%s'.\n", aPgmName, pBackup, sMake);
rc = RETURN_ERROR;
break;
}
/* Finish up */
if (bVerbose)
printf("%+-78s\r", "");
if (reader_close())
{
perror("mkdepend");
printf("%s: Error writing '%s'.\n", aPgmName, sMake);
rc = RETURN_ERROR;
break;
}
if (bMakeExists && chmod(sMake, aMakeStat.st_mode))
{
/* perror("mkdepend"); */
printf("%s: Warning: Can't update mode of '%s'.\n", aPgmName, sMake);
rc = RETURN_WARN;
}
if (pBackup && remove(pBackup))
{
perror("mkdepend");
printf("%s: Warning: Can't remove backup '%s'.\n", aPgmName, pBackup);
rc = RETURN_WARN;
break;
}
} while(0);
/* Error cleanup */
if (rc == RETURN_ERROR)
{
reader_close();
remove(sMake);
if (pBackup && rename(pBackup, sMake))
{
perror("mkdepend");
printf("%s: Can't restore '%s' from backup '%s'\n", aPgmName, sMake, pBackup);
}
}
if (bVerbose && rc != RETURN_ERROR)
printf("%+-78s\r", "");
if (pBackup)
free(pBackup);
return rc;
}
/*-------------------------------------------------------------------------*/
int main (int argc, char *argv[])
{
int i;
check_os2();
/* Determine the program executables name */
aPgmName = strdup(FilePart(argv[0]));
if (!aPgmName)
aPgmName = "mkdepend";
CheckStacksize(10240);
reader_init();
/* Get arguments, set up defaults */
getargs();
if (!aFiles.size)
{
if (add_expfile(&aFiles, "#?.c"))
exit_nomem(RETURN_FAIL);
}
if (!sObjExt)
sObjExt = ".o";
if (!aSrcExt.size)
{
if (array_addfile(&aSrcExt, ".c") || array_addfile(&aObjExt, NULL))
exit_nomem(RETURN_FAIL);
}
if (bVerbose)
{
printf("MkDepend %s (%s) -- Make Dependency Generator\n", VERSION, __DATE__);
puts("Copyright ⌐ 1995 Lars Dⁿning.");
putchar('\n');
}
/* Look for the Makefile to modify */
if (sMake)
{
bMakeExists = !stat(sMake, &aMakeStat);
}
else
{
sMake = "Makefile";
bMakeExists = !stat(sMake, &aMakeStat);
if (!bMakeExists)
{
sMake = "Makefile.mk";
bMakeExists = !stat(sMake, &aMakeStat);
}
if (!bMakeExists)
{
sMake = "DMakefile";
bMakeExists = !stat(sMake, &aMakeStat);
}
if (!bMakeExists)
{
sMake = "SMakefile";
bMakeExists = !stat(sMake, &aMakeStat);
}
if (!bMakeExists)
sMake = "Makefile";
}
/* Add the source files to the tree */
if (!aFiles.size)
{
printf("%s: No files given.\n", aPgmName);
set_rc(RETURN_WARN, 1);
}
for (i = 0; i < aFiles.size; i++)
{
if (nodes_addsource(aFiles.strs[i], 0))
exit_nomem(RETURN_FAIL);
}
/* Mark the exceptional files */
for (i = 0; i < aAvoid.size; i++)
{
if (nodes_addsource(aAvoid.strs[i], 1))
exit_nomem(RETURN_FAIL);
}
/* Read and analyse all those files */
set_rc(readfiles(), 0);
if (returncode < RETURN_ERROR)
set_rc(output(), 0);
if (returncode < RETURN_ERROR && bVerbose)
printf("%s '%s'.\n", bMakeExists ? "Updated" : "Created", sMake);
return returncode;
}
/***************************************************************************/